/* CSci4061 F2012 Assignment 3
 * section: 3
 * date: 11/10/12
 * name: Jeff Goin, Jack Jones
 * id: 2999885, 4220764 */

#include "mm_public.h"

/* Returns microseconds. */
double comp_time (struct timeval times, struct timeval timee)
{
	double elap = 0.0;

	if (timee.tv_sec > times.tv_sec) {
		elap += (((double)(timee.tv_sec - times.tv_sec -1))*1000000.0);
		elap += timee.tv_usec + (1000000-times.tv_usec);
	}
	else {
		elap = timee.tv_usec - times.tv_usec;
	}
	return ((unsigned long)(elap));
}


// mm_init 
// sets up memory block and list to manage it
// returns -1 on failure 0 on success
int mm_init (mm_t *MM, int tsz){
	
	if (tsz < 1) {
		return -1;
	}

	MM->size = tsz;
	MM->left = tsz;
	void *block = malloc(tsz);
	MM->head = (node*) malloc(tsz*sizeof(node));
	if (MM->head == NULL || block == NULL) {
		return -1;
	}
	MM->last = MM->head;

	node *a = MM->head;
	a->data = block;
	a->flag = 0;
	a->size = 0;
	a->nodeid = 1;

	node *b;
	int i;
	for (i = 1; i < tsz; i++) {
		block += 1;
		b = a + 1;
		a->next = b;
		b->flag = 0;
		b->next = MM->head;
		b->data = block;
		b->size = 0;
		b->nodeid = i +1;
		a = b;
	}
}


// mm_get
// allocates needed size
// returns pointer to the memory chunk
void* mm_get (mm_t *MM, int neededSize) {
	node* temp;
	temp = MM->head;
	int i = 0;
  
  //If space left is less than size requested return. 
	if (MM->left < neededSize) {
		perror("Not enough space left");
		return NULL;
	}
	while (i <= MM->size) {
		if (temp->flag == 1) {
			temp = temp->next;
			i++;
		}
    //Found unallocated node, make sure there is enough contiguous space.
		else {
			int j = i;
			node* temp2 = temp;
			while (j < (i + neededSize)) {
				if (temp2->flag == 1) {
					i++;
					temp = temp2->next;
					break;
				}
				else {
					temp2 = temp2->next;
					j++;
				}
			}
			if (j == (i + neededSize)) {
				MM->left -= neededSize;
				int k = j - neededSize;
				temp->size = neededSize;
				temp2 = temp;
				while (k < j) {
					temp2->flag = 1; 
					MM->last = temp2;
					temp2 = temp2->next;
					k++;
				}
				return temp->data;
			}
		}
	}			
}


// mm_put
// returns the taken chunk back to the memory manager
void mm_put (mm_t *MM, void *chunk) {
	node* temp;
	temp = MM->last;
	int i = 0;
	int j = 0;
	while (i < MM->size) {
		if (temp->flag == 1) {
			if (temp->data == chunk) {
				int chunksize = temp->size;
				while (j < chunksize) {
					temp->flag = 0;
					MM->last = temp;
					temp = temp->next;
					j++;
				}
				MM->left += chunksize;
			}
		}
		temp = temp ->next;
		i++;
	}
}


// mm_release
// frees the space taken by the memory manager
void mm_release (mm_t *MM) {
  node *temp = MM->head;
	free(temp->data);
	free(MM->head);
}
